import VRSim.Globals as globals

from VRSim.Node.XML import XML
from VRSim.Node.Domain import disk
from VRSim.Node.Interface import Interface

from VRSim.Utils import debug,  message

class CiscoDevices(XML):
    def __init__(self,  nodeid):
        XML.__init__(self, "devices")
        self.nodeid = nodeid
        self.emulator = "None"
        self.hdd = disk("file")
        self.maxSlot = 1
        self.slot = {
                    }
            
        # get console port number
        #self.console = globals.GApp.topology.getConsolePort(self.nodeid)
        self.console_ip = "127.0.0.1"
        self.console = globals.dynamips_console
        globals.dynamips_console += 1
    
    def getUnusedInterfaces(self,  linktype):
        """ return unused interfaces' dictionary
        return format
        'slot 0' : ['FastEthernet 0/1']
        'slot 1' : ['FastEthernet 1/1', 'FastEthernet 1/2']
        p.s. return same linktype of interface
        """
        # ex) linktype == globals.Enum.LinkType.Ethernet
        bandwidth = globals.bandWidth[linktype]
        adapterList = self.getAdapterFromBandwidth(bandwidth)
        # TEST
        print "getUnusedInterfaces adpaterList:(%s),(%s)" %(bandwidth,  adapterList)
        
        slotNames = self.slot.keys()
        slotNames.sort()
        # return value
        result = {}
        for slotName in slotNames:
            content = self.slot[slotName]
            # get adapter
            adapterContent = content["adapter"]
            adapter = adapterContent[0]
            maxIf = adapterContent[1]
            for possibleAdapter in adapterList:
                if adapter == possibleAdapter:
                    # adpater is matched
                    # find unused Interfaces of slot X
                    unusedIf = []
                    for portNumber in range(maxIf):
                        interfaceInstance = content[portNumber]
                        isEnabled = interfaceInstance.isEnabled
                        isAssigned = interfaceInstance.isAssigned
                        print "isEnabled or isAssigned",  isEnabled,  isAssigned
                        if isEnabled and (not isAssigned):
                            unusedIf.append(interfaceInstance.name)
                    # add unused Interfaces
                    if len(unusedIf) > 0:
                        result[slotName] = unusedIf
        if len(result.keys()) == 0:
            msg = "There is no unused Interface!"
            message(msg,  "warning")
            debug(msg)
            return False
        return result
                    
        
    def getInterface(self,  sn,  pn):
        # return interface instance
        sname = "slot " + str(sn)
        ports = self.slot[sname]
        interface = ports[int(pn)]
        return interface
    
    def getPossibleAdapter(self,  slot=0):
        """ return adapter and max interface
        return value is dictionary
        """
        debug(slot,  "CiscoDomain : getPossibleAdapter")
        if str(slot) == '0' or str(slot) == "slot 0":
            return {"C7200-IO-2FE" : 2,
                          "C7200-IO-GE-E" : 1 }
        else:
            return {"PA-GE" : 1, 
                        "PA-2FE-TX" : 2,
                          "PA-4E" : 4, 
                          "PA-8E" : 8 }
                          
    def getPossiblePorts(self,  slotName):
        debug("getPossiblePorts")
        
        ports = self.slot[slotName]
        adapter = ports["adapter"]
        length = adapter[1]
        result = []
        for i in range(length):
            interface = ports[i]
            result.append(interface.name)
           
        return result
     
    def getAdapterFromBandwidth(self,  bandWidth):
        if bandWidth == "E":
            return ["PA-4E",  "PA-8E"]
        elif bandWidth == "FE":
            return ["C7200-IO-2FE",  "PA-2FE-TX"]
        elif bandWidth == "GE":
            return ["C7200-IO-GE-E",  "PA-GE"]
        else:
            return ["PA-8E"]
    
        
    def isAssigned(self,  slotN,  portN):
        """ return interface is assigned or not
        """
        interface = self.getInterface(slotN,  portN)
        return interface.isAssigned
        
    def getBlankSlotNPort(self,  bandwidth):
        """ find first blank slot and port
        return: [slot number, port number]
                ex) [0, 2]
        """
        badapters = self.getAdapterFromBandwidth(bandwidth)
        slotNames = self.slot.keys()
        slotNames.sort()
        for slotName in slotNames:
            ports = self.slot[slotName]
            
            # find Bandwidth is same
            searchTF = False
            for badapter in badapters:
                if badapter == ports["adapter"][0]:
                    searchTF = True
            if searchTF == False:
                continue
            
            
            maxInterface = ( ports["adapter"] )[1]
            for port in range(maxInterface):
                interface = ports[port]
                if interface.isEnabled == True and interface.isAssigned == False:
                    debug("Blank Slot & Port:")
                    print interface.slot ,  interface.port
                    return [interface.slot,  interface.port]
        
        # not found
        # There is no blank interface
        # overwirte is needed
        return [0, 0]

    def updateNic(self,  sindex, pindex,   srcPort,  dstPort,  delay):
        """ update Network Interface card
        sindex = slot Index
        pindex = port Index
        1) set Assigned
        2) update Internal Link (srcPort, dstPort)
        """
        interface = self.getInterface(sindex,  pindex)
        interface.setAssigned()
        interface.setInternal(srcPort,  dstPort,  delay)

    def changeAdapter(self,  slotN,  nadapter):
        """ change Adapter
        if one of interface is isAssigned, can't change Adapter
        """
        slotName = "slot " + str(slotN)
        slot = self.slot[slotName]
        adapter = slot["adapter"]
        adapter[0] = nadapter
        adapter[1] = Adapter.MaxInterface[nadapter]
        for i in range(adapter[1]):
            interface = self.slot[i]
            interface.changeAdapter(nadapter)
            interface.setEnabled(True)
      
    def clearInterface(self,  ifName):
        (slotN,  portN) = self.getSlotNPortByName(ifName)
        
        if slotN == None:
            return False
        
        interface = self.getInterface(slotN,  portN)
        interface.setClear()
        
        
    def getSlotNPortByName(self,  ifName):
        debug(ifName)
        keys = self.slot.keys()
        keys.sort()
        slotN = 0
        for slotName in keys:
            slot = self.slot[slotName]
            adapter = slot['adapter']
            for portN in range(adapter[1]):
                interface = slot[portN]
                debug(interface.name)
                if interface.name == ifName:
                    return (slotN,  portN)
                # adapter is different
            slotN = slotN + 1
        return None
        
    #########################
    # XML
    ##########################
    def getXML(self):
        devices = self.xml.createElement("devices")
        emulator = self.xml.createElement("emulator")
        emulatorText =self.xml.createTextNode(self.emulator)
        emulator.appendChild(emulatorText)
        hdd = self.hdd.getXML()
        # TODO: cdrom check
        #cdrom = self.cdrom.getXML()
        
        # appendChild
        devices.appendChild(emulator)
        devices.appendChild(hdd)
        
        # NIC
        keys = self.slot.keys()
        keys.sort()
        for slotName in keys:
            slot = self.slot[slotName]
            adapter = slot['adapter']
            maxInterface = adapter[1]
            for i in range(maxInterface):
                interface = slot[i]
                # check isEnabled
                if interface.isEnabled == False:
                    continue
                xml = interface.getXML()
                devices.appendChild(xml)
        
        
        #<console type='tcp'>
        #<source mode='bind' host='127.0.0.1' service='8001'/>
        #<protocol type='raw'/>
        #<target port='0'/>
        #</console>
        # Cisco router has only console port
        # Console connection
        """
        console = self.xml.createElement("console")
        console.setAttribute("type", "pty")
        target = self.xml.createElement("target")
        target.setAttribute("port", "0")
        console.appendChild(target)
        devices.appendChild(console)
        """
        
        console = self.xml.createElement("console")
        console.setAttribute("type", "tcp")
        source = self.xml.createElement("source")
        source.setAttribute("mode",  "bind")
        # find remote VM's IP
        self.console_ip = globals.GApp.topology.getVMAPIIP(self.nodeid)
        source.setAttribute("host",  self.console_ip)
        source.setAttribute("service",  str(self.console) )
        protocol = self.xml.createElement("protocol")
        protocol.setAttribute("type",  "raw")
        target = self.xml.createElement("target")
        target.setAttribute("port", "0")
        console.appendChild(source)
        console.appendChild(protocol)
        console.appendChild(target)
        devices.appendChild(console)
            
        return devices
        
    def setXML(self,  devices):
        #self.emulator = "/usr/local/bin/qemu-system-x86_64"
        #self.hdd = disk()
        #self.hasCDROM = True
        #self.cdrom = disk(device="cdrom")
        #self.hasFloopy = False
        #self.floopy = disk(device="floopy")
        node_emulator = devices.getElementsByTagName("emulator")[0]
        self.emulator = node_emulator.firstChild.data
        disks = devices.getElementsByTagName("disk")
        
        # Disks
        for disk in disks:
            device_list = disk.getAttribute("device")
            if device_list == "disk":
                self.hdd.setXML(disk)
            elif device_list == "cdrom":
                self.cdrom.setXML(disk)
            elif device_list == "floopy":
                self.floopy.setXML(disk)
            else:
                debug("Unkown devices : ")
                debug(self.disk.toprettyxml())
                pass
        
        # Network Interface Cards
        interfaces = devices.getElementsByTagName("interface")
        for interface in interfaces:
            
            # Interface setting
            slot = interface.getAttribute("slot")
            port = interface.getAttribute("port")
            
            # adapter setting
            model = interface.getElementsByTagName("model")
            if model:
                adapterName = model[0].getAttribute("type")
                slotObj = self.slot["slot " + str(slot)]
                adapter = slotObj["adapter"]
                # adapter kind
                adapter[0] = adapterName
                # maxInterface
                dic = self.getPossibleAdapter(int(slot))
                print dic
                maxInf = dic[str(adapterName)]
                adapter[1] = maxInf
                
            interfaceInstance = self.getInterface(slot,  port)
            interfaceInstance.model = "cisco"
            interfaceInstance.setXML(interface)
            
        # TODO
        # console port
